home *** CD-ROM | disk | FTP | other *** search
- /* -----------------------------------------------------------------------------
-
- timer.api ©1999 Dietmar Eilert
-
- API plug-in. This example demonstrates message port handling. Dice:
-
- DMAKE
-
- -------------------------------------------------------------------------------
-
- */
-
- #include "defs.h"
-
- /// "prototypes"
-
- // library functions
-
- Prototype LibCall struct APIClient *APIMountClient(__A0 struct APIMessage *, __A1 char *);
- Prototype LibCall void APICloseClient(__A0 struct APIClient *, __A1 struct APIMessage *);
- Prototype LibCall void APIBriefClient(__A0 struct APIClient *, __A1 struct APIMessage *);
- Prototype LibCall void APIFree (__A0 struct APIClient *, __A1 struct APIOrder *);
-
- // private functions
-
- Prototype struct HostContext *AddHost (struct Task *);
- Prototype void AddTimerEvent (struct HostContext *);
- Prototype ULONG Dispatch (struct APIClient *, struct APIMessage *);
- Prototype struct HostContext *FindContext (struct Task *);
- Prototype void RemoveHost (struct HostContext *);
-
- ///
- /// "globals"
-
- struct List HostList;
-
- ///
- /// "library functions"
-
- LibCall struct APIClient *
- APIMountClient(__A0 struct APIMessage *apiMsg, __A1 char *args)
- {
- struct PlugInContext *plugInContext;
-
- if (plugInContext = (struct PlugInContext *)AllocVec(sizeof(struct PlugInContext), MEMF_CLEAR | MEMF_PUBLIC)) {
-
- struct HostContext *hostContext;
- struct Task *task;
-
- task = FindTask(NULL);
-
- // find context of host task (or allocate new context if a new host starts using this plug-in)
-
- hostContext = FindContext(task);
-
- if (hostContext == NULL)
-
- hostContext = AddHost(task);
-
- if (hostContext) {
-
- // track number of plug-in instances used by host task
-
- ++hostContext->OpenCount;
-
- // build plug-in description for host
-
- plugInContext->APIClient.api_APIVersion = API_INTERFACE_VERSION;
- plugInContext->APIClient.api_Version = 1;
- plugInContext->APIClient.api_Name = "Timer";
- plugInContext->APIClient.api_Info = "API example";
- plugInContext->APIClient.api_Commands = NULL;
- plugInContext->APIClient.api_Serial = 0;
- plugInContext->APIClient.api_Classes = API_CLASS_SYSTEM;
- plugInContext->APIClient.api_Area = NULL;
- plugInContext->APIClient.api_Signals = 1L<<(hostContext->TimerPort->mp_SigBit);
-
- // remember host context for this instance
-
- plugInContext->HostContext = hostContext;
- }
- else {
-
- FreeVec(plugInContext);
-
- plugInContext = NULL;
- }
- }
-
- return((struct APIClient *)plugInContext);
- }
-
- LibCall void
- APICloseClient(__A0 struct APIClient *handle, __A1 struct APIMessage *apiMsg)
- {
- if (handle) {
-
- struct HostContext *context;
-
- // find host context for this plug-in instance
-
- context = ((struct PlugInContext *)handle)->HostContext;
-
- // check open count (closing last instance used by this task ?)
-
- if (context->OpenCount > 1) {
-
- --context->OpenCount;
- }
- else
- RemoveHost(context);
-
- FreeVec(handle);
- }
- }
-
- LibCall void
- APIBriefClient(__A0 struct APIClient *handle, __A1 struct APIMessage *apiMsg)
- {
- struct APIMessage *msg;
-
- // handle host's command notify
-
- for (msg = apiMsg; msg; msg = msg->api_Next) {
-
- if (msg->api_State == API_STATE_NOTIFY) {
-
- switch (msg->api_Class) {
-
- case API_CLASS_SYSTEM:
-
- switch (msg->api_Action) {
-
- case API_ACTION_SIGNAL:
-
- {
- struct HostContext *context;
-
- // find host task context for this plug-in instance
-
- if (context = ((struct PlugInContext *)handle)->HostContext) {
-
- ULONG signal = 1L<<(context->TimerPort->mp_SigBit);
-
- // is this our signal ?
-
- if (signal & (ULONG)apiMsg->api_Data) {
-
- struct timerequest *timerequest;
-
- // process event
-
- msg->api_Error = Dispatch(handle, apiMsg);
-
- // the first plug-in instance seeing this signal gets the actual message and reinitializes the timer)
-
- if (timerequest = (struct timerequest *)GetMsg(context->TimerPort)) {
-
- FreeVec(timerequest);
-
- // no pending timer requests for this host
-
- context->IOPending = NULL;
-
- // restart timer for this host
-
- AddTimerEvent(context);
- }
- }
- }
- }
-
- break;
-
- default:
-
- msg->api_Error = API_ERROR_UNKNOWN;
- }
-
- break;
-
- default:
-
- msg->api_Error = API_ERROR_UNKNOWN;
- }
- }
- }
- }
-
- LibCall void
- APIFree(__A0 struct APIClient *handle, __A1 struct APIOrder *apiOrder)
- {
- // no ressources to be freed
- }
-
- ///
- /// "private"
-
- /* -------------------------------- FindContext --------------------------------
-
- Find context for this task. A "context" is a structure allocated for each host
- task (ie. each GoldED task) using this plug-in. It holds task-specific data.
- The concept of contexts is used because the resources used by this plug-in
- (specifically message ports) may only be allocated and used on a per-task
- basis undrer AmigaOS3.
-
- */
-
- struct HostContext *
- FindContext(task)
-
- struct Task *task;
- {
- struct HostContext *context;
-
- for (context = (struct HostContext *)HostList.lh_Head; context->Node.ln_Succ; context = (struct HostContext *)context->Node.ln_Succ)
-
- if (context->Task == task)
-
- return(context);
-
- return(NULL);
- }
-
-
- /* ---------------------------------- AddHost ----------------------------------
-
- Add host to list of registered hosts, allocate resources (e.g. one message
- port per host) and start the timer. Usually a plug-in is used by one host
- only but theoretically plug-ins can be used by multiple hosts simultaneously.
-
- */
-
- struct HostContext *
- AddHost(task)
-
- struct Task *task;
- {
- struct HostContext *context;
-
- if (context = (struct HostContext *)AllocVec(sizeof(struct HostContext), MEMF_CLEAR | MEMF_PUBLIC)) {
-
- context->Task = task;
-
- if (context->TimerPort = CreateMsgPort()) {
-
- if (context->TimeRequest = (struct timerequest *)CreateExtIO(context->TimerPort, sizeof(struct timerequest))) {
-
- if (OpenDevice(TIMERNAME, UNIT_VBLANK, (struct IORequest *)context->TimeRequest, 0) == 0) {
-
- AddTail(&HostList, &context->Node);
-
- // start timer (create initial timer request)
-
- AddTimerEvent(context);
-
- return(context);
- }
-
- DeleteExtIO((struct IORequest *)context->TimeRequest);
- }
-
- DeleteMsgPort(context->TimerPort);
- }
-
- FreeVec(context);
- }
-
- return(NULL);
- }
-
-
- /* -------------------------------- RemoveHost ---------------------------------
-
- Remove host from list of registered hosts (stop the timer for this host).
-
- */
-
- void
- RemoveHost(context)
-
- struct HostContext *context;
- {
- Remove(&context->Node);
-
- if (context->IOPending) {
-
- AbortIO((struct IORequest *)context->IOPending);
-
- WaitIO ((struct IORequest *)context->IOPending);
-
- FreeVec(context->IOPending);
- }
-
- if (context->TimeRequest) {
-
- CloseDevice((struct IORequest *)context->TimeRequest);
-
- DeleteExtIO((struct IORequest *)context->TimeRequest);
- }
-
- if (context->TimerPort) {
-
- struct Message *msg;
-
- while (msg = (struct Message *)GetMsg(context->TimerPort))
-
- ReplyMsg(msg);
-
- DeleteMsgPort(context->TimerPort);
- }
-
- FreeVec(context);
- }
-
-
- /* ----------------------------------- AddTimerEvent ---------------------------
-
- Send timer event (wait one second)
-
- */
-
- void
- AddTimerEvent(context)
-
- struct HostContext *context;
- {
- // no timer event pending ?
-
- if (context->IOPending == NULL) {
-
- if (context->IOPending = (struct timerequest *)AllocVec(sizeof(struct timerequest), MEMF_ANY | MEMF_PUBLIC)) {
-
- // initialize IORequest
-
- *context->IOPending = *context->TimeRequest;
-
- // wait for one second
-
- context->IOPending->tr_node.io_Command = TR_ADDREQUEST;
- context->IOPending->tr_time.tv_secs = 1;
-
- SendIO((struct IORequest *)context->IOPending);
- }
- }
- }
-
-
- /* --------------------------------- Dispatch ----------------------------------
-
- Dispatch timer even. We do NOT consume this event (by setting apiMsg->api_State
- to API_STATE_CONSUMED) so that other instances of this plug-in using the same
- timer can see the event, too.
-
- */
-
- ULONG
- Dispatch(handle, apiMsg)
-
- struct APIClient *handle;
- struct APIMessage *apiMsg;
- {
- static UBYTE *quotes[] = {
-
- "Cheer up, Brian. You know what they say."
- "Some things in life are bad,",
- "They can really make you mad.",
- "Other things just make you swear and curse.",
- "When you're chewing on life's grissle,",
- "Don't grumble, give a whistle.",
- "And this'll help things turn out for the best,"
- "And...",
- "Always look on the bright side of life",
- "Always look on the bright side of life",
- NULL
- };
-
- static UWORD next = 0;
-
- // set status text
-
- apiMsg->api_Status = quotes[next];
-
- // activate next string
-
- if (quotes[++next] == NULL)
-
- next = 0;
-
- return(API_ERROR_OK);
- }
-
-
- ///
-